/*-----------------------------------------------------------------------------------*/
/* Nuvoton Technology Corporation confidential                                       */
/*                                                                                   */
/* Copyright (c) 2008 by Nuvoton Technology Corporation                              */
/* All rights reserved                                                               */
/*                                                                                   */
/*-----------------------------------------------------------------------------------*/
#include <stdlib.h>
#include <string.h>

#include "nuc900_reg.h"
#include "wbio.h"
#include "nuc900_gnand.h"
#include "nuc900_sic.h"
#include "gnand_global.h"
#include "wblib.h"
#include "fmi.h"

#define FMI_SM_READ		0
#define FMI_SM_WRITE	1
#define FMI_SM_ERASE	2
CHAR volatile _fmi_nPreState = 0xFF;

extern BOOL volatile _fmi_bIsSMDataReady;

/* functions */
INT fmiSMCheckRB()
{
	unsigned int volatile tick;
	tick = sysGetTicks(TIMER0);

	while(1)
	{
		if (inpw(REG_SMISR) & 0x400)
		{
			outpw(REG_SMISR, 0x400);
			return 1;
		}

		if ((sysGetTicks(TIMER0) - tick) > 1000)
			break;
	}
	return 0;
}

// SM functions
INT fmiSM_Reset(VOID)
{
	UINT32 volatile i;

	outpw(REG_SMCMD, 0xff);
	for (i=100; i>0; i--);

	if (!fmiSMCheckRB())
		return FMI_SM_RB_ERR;
	return 0;
}


VOID fmiSM_Initial(FMI_SM_INFO_T *pSM)
{
	if (pSM->bIs2KPageSize)
		outpw(REG_SMCSR, (inpw(REG_SMCSR)&0xfffffff0)|0x00000008);	// psize:2048; wp# set 1
	else
		outpw(REG_SMCSR, (inpw(REG_SMCSR)&0xfffffff0)|0x00000000);	// psize:512; wp# set 1

	outpw(REG_SMIER, 0x01);
}


BOOL gbIsSupport2PlaneNand = FALSE;
INT fmiSM_ReadID(FMI_SM_INFO_T *pSM, NDISK_T *NDISK_info)
{
	UINT32 tempID[5];

	fmiSM_Reset();
	outpw(REG_SMCMD, 0x90);		// read ID command
	outpw(REG_SMADDR, 0x80000000);	// address 0x00

	tempID[0] = inpw(REG_SMDATA);
	tempID[1] = inpw(REG_SMDATA);
	tempID[2] = inpw(REG_SMDATA);
	tempID[3] = inpw(REG_SMDATA);
	tempID[4] = inpw(REG_SMDATA);

	NDISK_info->vendor_ID = tempID[0];
	NDISK_info->device_ID = tempID[1];

	switch (tempID[1])
	{
		/* page size 512B */
		case 0x79:	// 128M
			pSM->uSectorPerFlash = 255744;
			pSM->uBlockPerFlash = 8191;
			pSM->uPagePerBlock = 32;
			pSM->uSectorPerBlock = 32;
			pSM->bIsMulticycle = TRUE;
			pSM->bIs2KPageSize = FALSE;

			NDISK_info->NAND_type = NAND_TYPE_SLC;
			NDISK_info->nZone = 8;				/* number of zones */
			NDISK_info->nBlockPerZone = 1024;	/* blocks per zone */
			NDISK_info->nPagePerBlock = 32;		/* pages per block */
			NDISK_info->nLBPerZone = 1000;		/* logical blocks per zone */
			NDISK_info->nPageSize = 512;
			break;

		case 0x76:	// 64M
			pSM->uSectorPerFlash = 127872;
			pSM->uBlockPerFlash = 4095;
			pSM->uPagePerBlock = 32;
			pSM->uSectorPerBlock = 32;
			pSM->bIsMulticycle = TRUE;
			pSM->bIs2KPageSize = FALSE;

			NDISK_info->NAND_type = NAND_TYPE_SLC;
			NDISK_info->nZone = 4;				/* number of zones */
			NDISK_info->nBlockPerZone = 1024;	/* blocks per zone */
			NDISK_info->nPagePerBlock = 32;		/* pages per block */
			NDISK_info->nLBPerZone = 1000;		/* logical blocks per zone */
			NDISK_info->nPageSize = 512;
			break;

		case 0x75:	// 32M
			pSM->uSectorPerFlash = 63936;
			pSM->uBlockPerFlash = 2047;
			pSM->uPagePerBlock = 32;
			pSM->uSectorPerBlock = 32;
			pSM->bIsMulticycle = FALSE;
			pSM->bIs2KPageSize = FALSE;

			NDISK_info->NAND_type = NAND_TYPE_SLC;
			NDISK_info->nZone = 2;				/* number of zones */
			NDISK_info->nBlockPerZone = 1024;	/* blocks per zone */
			NDISK_info->nPagePerBlock = 32;		/* pages per block */
			NDISK_info->nLBPerZone = 1000;		/* logical blocks per zone */
			NDISK_info->nPageSize = 512;
			break;

		case 0x73:	// 16M
			pSM->uSectorPerFlash = 31968;	// max. sector no. = 999 * 32
			pSM->uBlockPerFlash = 1023;
			pSM->uPagePerBlock = 32;
			pSM->uSectorPerBlock = 32;
			pSM->bIsMulticycle = FALSE;
			pSM->bIs2KPageSize = FALSE;

			NDISK_info->NAND_type = NAND_TYPE_SLC;
			NDISK_info->nZone = 1;				/* number of zones */
			NDISK_info->nBlockPerZone = 1024;	/* blocks per zone */
			NDISK_info->nPagePerBlock = 32;		/* pages per block */
			NDISK_info->nLBPerZone = 1000;		/* logical blocks per zone */
			NDISK_info->nPageSize = 512;
			break;

		/* page size 2KB */
		case 0xf1:	// 128M
			pSM->uBlockPerFlash = 1023;
			pSM->uPagePerBlock = 64;
			pSM->uSectorPerBlock = 256;
			pSM->uSectorPerFlash = 255744;
			pSM->bIsMulticycle = FALSE;
			pSM->bIs2KPageSize = TRUE;

			NDISK_info->NAND_type = NAND_TYPE_SLC;
			NDISK_info->nZone = 1;				/* number of zones */
			NDISK_info->nBlockPerZone = 1024;	/* blocks per zone */
			NDISK_info->nPagePerBlock = 64;		/* pages per block */
			NDISK_info->nLBPerZone = 1000;		/* logical blocks per zone */
			NDISK_info->nPageSize = 2048;
			break;

		case 0xda:	// 256M
			if ((tempID[3] & 0x33) == 0x11)
			{
				pSM->uBlockPerFlash = 2047;
				pSM->uPagePerBlock = 64;
				pSM->uSectorPerBlock = 256;

				NDISK_info->NAND_type = NAND_TYPE_SLC;
				NDISK_info->nZone = 2;				/* number of zones */
				NDISK_info->nPagePerBlock = 64;		/* pages per block */
			}
			else if ((tempID[3] & 0x33) == 0x21)
			{
				pSM->uBlockPerFlash = 1023;
				pSM->uPagePerBlock = 128;
				pSM->uSectorPerBlock = 512;
				pSM->bIsMLCNand = TRUE;

				NDISK_info->NAND_type = NAND_TYPE_MLC;
				NDISK_info->nZone = 1;				/* number of zones */
				NDISK_info->nPagePerBlock = 128;	/* pages per block */
			}
			pSM->uSectorPerFlash = 511488;
			pSM->bIsMulticycle = TRUE;
			pSM->bIs2KPageSize = TRUE;

			NDISK_info->nBlockPerZone = 1024;	/* blocks per zone */
			NDISK_info->nLBPerZone = 1000;		/* logical blocks per zone */
			NDISK_info->nPageSize = 2048;
			break;

		case 0xdc:	// 512M
			if ((tempID[3] & 0x33) == 0x11)
			{
				pSM->uBlockPerFlash = 4095;
				pSM->uPagePerBlock = 64;
				pSM->uSectorPerBlock = 256;

				NDISK_info->NAND_type = NAND_TYPE_SLC;
				NDISK_info->nZone = 4;				/* number of zones */
				NDISK_info->nPagePerBlock = 64;		/* pages per block */
			}
			else if ((tempID[3] & 0x33) == 0x21)
			{
				pSM->uBlockPerFlash = 2047;
				pSM->uPagePerBlock = 128;
				pSM->uSectorPerBlock = 512;
				pSM->bIsMLCNand = TRUE;

				NDISK_info->NAND_type = NAND_TYPE_MLC;
				NDISK_info->nZone = 2;				/* number of zones */
				NDISK_info->nPagePerBlock = 128;	/* pages per block */
			}
			pSM->uSectorPerFlash = 1022976;
			pSM->bIsMulticycle = TRUE;
			pSM->bIs2KPageSize = TRUE;

			NDISK_info->nBlockPerZone = 1024;	/* blocks per zone */
			NDISK_info->nLBPerZone = 1000;		/* logical blocks per zone */
			NDISK_info->nPageSize = 2048;
			break;

		case 0xd3:	// 1024M
			if ((tempID[3] & 0x33) == 0x11)
			{
				pSM->uBlockPerFlash = 8191;
				pSM->uPagePerBlock = 64;
				pSM->uSectorPerBlock = 256;

				NDISK_info->NAND_type = NAND_TYPE_SLC;
				NDISK_info->nZone = 8;				/* number of zones */
				NDISK_info->nPagePerBlock = 64;		/* pages per block */
			}
			else if ((tempID[3] & 0x33) == 0x21)
			{
				pSM->uBlockPerFlash = 4095;
				pSM->uPagePerBlock = 128;
				pSM->uSectorPerBlock = 512;
				pSM->bIsMLCNand = TRUE;

				NDISK_info->NAND_type = NAND_TYPE_MLC;
				NDISK_info->nZone = 4;				/* number of zones */
				NDISK_info->nPagePerBlock = 128;	/* pages per block */
			}
			pSM->uSectorPerFlash = 2045952;
			pSM->bIsMulticycle = TRUE;
			pSM->bIs2KPageSize = TRUE;

			NDISK_info->nBlockPerZone = 1024;	/* blocks per zone */
			NDISK_info->nLBPerZone = 1000;		/* logical blocks per zone */
			NDISK_info->nPageSize = 2048;
			break;

		case 0xd5:	// 2048M
			if ((tempID[3] & 0x33) == 0x11)
			{
				pSM->uBlockPerFlash = 16383;
				pSM->uPagePerBlock = 64;
				pSM->uSectorPerBlock = 256;

				NDISK_info->NAND_type = NAND_TYPE_SLC;
				NDISK_info->nZone = 16;				/* number of zones */
				NDISK_info->nPagePerBlock = 64;		/* pages per block */
			}
			else if ((tempID[3] & 0x33) == 0x21)
			{
				pSM->uBlockPerFlash = 8191;
				pSM->uPagePerBlock = 128;
				pSM->uSectorPerBlock = 512;
				pSM->bIsMLCNand = TRUE;

				NDISK_info->NAND_type = NAND_TYPE_MLC;
				NDISK_info->nZone = 8;				/* number of zones */
				NDISK_info->nPagePerBlock = 128;	/* pages per block */
			}
			pSM->uSectorPerFlash = 4091904;
			pSM->bIsMulticycle = TRUE;
			pSM->bIs2KPageSize = TRUE;

			NDISK_info->nBlockPerZone = 1024;	/* blocks per zone */
			NDISK_info->nLBPerZone = 1000;		/* logical blocks per zone */
			NDISK_info->nPageSize = 2048;

#if 1
			if (tempID[0] == 0xec)
			{
				gbIsSupport2PlaneNand = TRUE;
				NDISK_info->nZone = 4;				/* number of zones */
				NDISK_info->nPageSize = 4096;
			}
#endif
			break;

		default:
#ifdef DEBUG
			printf("SM ID not support!![%x][%x]\n", tempID[0], tempID[1]);
#endif
			return FMI_SM_ID_ERR;
	}

#ifdef DEBUG
	printf("SM ID [%x][%x][%x][%x]\n", tempID[0], tempID[1], tempID[2], tempID[3]);
#endif
	return 0;
}


INT fmiSM2BufferM(FMI_SM_INFO_T *pSM, UINT32 uSector, UINT8 ucColAddr)
{
	if ((_fmi_nPreState == FMI_SM_WRITE) || (_fmi_nPreState == FMI_SM_ERASE))
	{
		if (!fmiSMCheckRB())
			return FMI_SM_RB_ERR;

		outpw(REG_SMCMD, 0x70);		// status read command
		if (inpw(REG_SMDATA) & 0x01)	// 1:fail; 0:pass
		{
#ifdef DEBUG
			printf("fmiSM_Write_512: data error!!\n");
#endif
			return FMI_SM_STATE_ERROR;
		}
	}

	if (_fmi_nPreState == FMI_SM_READ)
	{
		/* clear R/B flag */
		while(!(inpw(REG_SMISR) & 0x40000));
		outpw(REG_SMISR, 0x400);
	}
	outpw(REG_SMCMD, 0x00);		// read command
	outpw(REG_SMADDR, ucColAddr);	// CA0 - CA7
	outpw(REG_SMADDR, uSector & 0xff);	// PA0 - PA7
	if (!pSM->bIsMulticycle)
		outpw(REG_SMADDR, ((uSector >> 8) & 0xff)|0x80000000);		// PA8 - PA15
	else
	{
		outpw(REG_SMADDR, (uSector >> 8) & 0xff);		// PA8 - PA15
		outpw(REG_SMADDR, ((uSector >> 16) & 0xff)|0x80000000);		// PA16 - PA17
	}
	_fmi_nPreState = FMI_SM_READ;

	if (!fmiSMCheckRB())
		return FMI_SM_RB_ERR;

	return 0;
}


INT fmiSM2BufferM_RA(FMI_SM_INFO_T *pSM, UINT32 uSector, UINT8 ucColAddr)
{
	if ((_fmi_nPreState == FMI_SM_WRITE) || (_fmi_nPreState == FMI_SM_ERASE))
	{
		if (!fmiSMCheckRB())
			return FMI_SM_RB_ERR;

		outpw(REG_SMCMD, 0x70);		// status read command
		if (inpw(REG_SMDATA) & 0x01)	// 1:fail; 0:pass
		{
#ifdef DEBUG
			printf("fmiSM_Write_512: data error!!\n");
#endif
			return FMI_SM_STATE_ERROR;
		}
	}

	if (_fmi_nPreState == FMI_SM_READ)
	{
		/* clear R/B flag */
		while(!(inpw(REG_SMISR) & 0x40000));
		outpw(REG_SMISR, 0x400);
	}
	outpw(REG_SMCMD, 0x50);		// read command
	outpw(REG_SMADDR, ucColAddr);	// CA0 - CA7
	outpw(REG_SMADDR, uSector & 0xff);	// PA0 - PA7
	if (!pSM->bIsMulticycle)
		outpw(REG_SMADDR, ((uSector >> 8) & 0xff)|0x80000000);		// PA8 - PA15
	else
	{
		outpw(REG_SMADDR, (uSector >> 8) & 0xff);		// PA8 - PA15
		outpw(REG_SMADDR, ((uSector >> 16) & 0xff)|0x80000000);		// PA16 - PA17
	}
	_fmi_nPreState = FMI_SM_READ;

	if (!fmiSMCheckRB())
		return FMI_SM_RB_ERR;

	return 0;
}


INT fmiSMCorrectData_512(UINT32 uDAddr)
{
	UINT32 volatile reg, byte;
	unsigned int volatile data, errCount;

	reg = inpw(REG_ECC4ST);

	if (reg & 0x02)
	{
#ifdef DEBUG
		printf("uncorrectable!!\n");
#endif
		return FMI_SM_ECC_ERROR;
	}
	else if (reg & 0x01)
	{
		errCount = (inpw(REG_ECC4ST) >> 2) & 0x7;
		switch (errCount)
		{
			case 1:
				byte = inpw(REG_ECC4F1A1) & 0x1ff;
				data = inpw(REG_ECC4F1D) & 0xff;
				writeb(uDAddr+byte, readb(uDAddr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 1 byte!! byte[%d], data[%d]\n", byte, data);
#endif
				break;

			case 2:
				byte = inpw(REG_ECC4F1A1) & 0x1ff;
				data = inpw(REG_ECC4F1D) & 0xff;
				writeb(uDAddr+byte, readb(uDAddr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 1 byte!! byte[%d], data[%d]\n", byte, data);
#endif
				byte = (inpw(REG_ECC4F1A1) >> 16) & 0x1ff;
				data = (inpw(REG_ECC4F1D) >> 8) & 0xff;
				writeb(uDAddr+byte, readb(uDAddr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 2 byte!! byte[%d], data[%d]\n", byte, data);
#endif
				break;

			case 3:
				byte = inpw(REG_ECC4F1A1) & 0x1ff;
				data = inpw(REG_ECC4F1D) & 0xff;
				writeb(uDAddr+byte, readb(uDAddr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 1 byte!! byte[%d], data[%d]\n", byte, data);
#endif
				byte = (inpw(REG_ECC4F1A1) >> 16) & 0x1ff;
				data = (inpw(REG_ECC4F1D) >> 8) & 0xff;
				writeb(uDAddr+byte, readb(uDAddr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 2 byte!! byte[%d], data[%d]\n", byte, data);
#endif
				byte = inpw(REG_ECC4F1A2) & 0x1ff;
				data = (inpw(REG_ECC4F1D) >> 16) & 0xff;
				writeb(uDAddr+byte, readb(uDAddr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 3 byte!! byte[%d], data[%d]\n", byte, data);
#endif
				break;

			case 4:
				byte = inpw(REG_ECC4F1A1) & 0x1ff;
				data = inpw(REG_ECC4F1D) & 0xff;
				writeb(uDAddr+byte, readb(uDAddr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 1 byte!! byte[%d], data[%d]\n", byte, data);
#endif
				byte = (inpw(REG_ECC4F1A1) >> 16) & 0x1ff;
				data = (inpw(REG_ECC4F1D) >> 8) & 0xff;
				writeb(uDAddr+byte, readb(uDAddr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 2 byte!! byte[%d], data[%d]\n", byte, data);
#endif
				byte = inpw(REG_ECC4F1A2) & 0x1ff;
				data = (inpw(REG_ECC4F1D) >> 16) & 0xff;
				writeb(uDAddr+byte, readb(uDAddr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 3 byte!! byte[%d], data[%d]\n", byte, data);
#endif
				byte = (inpw(REG_ECC4F1A2) >> 16) & 0x1ff;
				data = (inpw(REG_ECC4F1D) >> 24) & 0xff;
				writeb(uDAddr+byte, readb(uDAddr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 4 byte!! byte[%d], data[%d]\n", byte, data);
#endif
				break;
		}
	}

	return 0;
}


INT fmiSM_Read_512(FMI_SM_INFO_T *pSM, UINT32 uSector, UINT32 uDAddr)
{
	outpw(REG_DMACSAR2, uDAddr);

	fmiSM2BufferM(pSM, uSector, 0);

	_fmi_bIsSMDataReady = FALSE;
	outpw(REG_SMCSR, inpw(REG_SMCSR) | 0x02);
	while(!_fmi_bIsSMDataReady);

	// check ECC
	if (inpw(REG_SMISR) & 0x02)
	{
#ifdef DEBUG
		printf("ECC error Sector[%x]\n", uSector);
#endif
		outpw(REG_SMISR, 0x02);
		return fmiSMCorrectData_512(uDAddr);
	}

	return 0;
}


VOID fmiBuffer2SMM(FMI_SM_INFO_T *pSM, UINT32 uSector, UINT8 ucColAddr)
{
	// set the spare area configuration
	/* write byte 514, 515 as used page */
	outpw(REG_SMRA_0, 0x0000FFFF);

	// send command
	outpw(REG_SMCMD, 0x80);		// serial data input command
	outpw(REG_SMADDR, ucColAddr);	// CA0 - CA7
	outpw(REG_SMADDR, uSector & 0xff);	// PA0 - PA7
	if (!pSM->bIsMulticycle)
		outpw(REG_SMADDR, ((uSector >> 8) & 0xff)|0x80000000);		// PA8 - PA15
	else
	{
		outpw(REG_SMADDR, (uSector >> 8) & 0xff);		// PA8 - PA15
		outpw(REG_SMADDR, ((uSector >> 16) & 0xff)|0x80000000);		// PA16 - PA17
	}
}


INT fmiSM_Write_512(FMI_SM_INFO_T *pSM, UINT32 uSector, UINT32 uSAddr)
{
	if ((_fmi_nPreState == FMI_SM_WRITE) || (_fmi_nPreState == FMI_SM_ERASE))
	{
		if (!fmiSMCheckRB())
			return FMI_SM_RB_ERR;

		outpw(REG_SMCMD, 0x70);		// status read command
		if (inpw(REG_SMDATA) & 0x01)	// 1:fail; 0:pass
		{
#ifdef DEBUG
			printf("fmiSM_Write_512: data error!!\n");
#endif
			return FMI_SM_STATE_ERROR;
		}
	}

	if (_fmi_nPreState == FMI_SM_READ)
	{
		/* clear R/B flag */
		while(!(inpw(REG_SMISR) & 0x40000));
		outpw(REG_SMISR, 0x400);
	}

	outpw(REG_DMACSAR2, uSAddr);
	fmiBuffer2SMM(pSM, uSector, 0);

	_fmi_bIsSMDataReady = FALSE;
	outpw(REG_SMCSR, inpw(REG_SMCSR) | 0x04);
	while(!_fmi_bIsSMDataReady);

	outpw(REG_SMCMD, 0x10);		// auto program command
	_fmi_nPreState = FMI_SM_WRITE;

	return 0;
}


INT fmiSMCorrectData_2K(UINT32 uDAddr)
{
	UINT32 volatile byte, correct_addr;
	unsigned int volatile reg, data, errCount;

	reg = inpw(REG_ECC4ST);

	if ((reg & 0x02) || (reg & 0x200) || (reg & 0x20000) || (reg & 0x2000000))
	{
#ifdef DEBUG
		printf("uncorrectable!!\n");
#endif
		return FMI_SM_ECC_ERROR;
	}
	else if (reg & 0x01)
	{
		errCount = (inpw(REG_ECC4ST) >> 2) & 0x7;
		correct_addr = uDAddr;
		switch (errCount)
		{
			case 1:
				byte = inpw(REG_ECC4F1A1) & 0x1ff;
				data = inpw(REG_ECC4F1D) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 1 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				break;

			case 2:
				byte = inpw(REG_ECC4F1A1) & 0x1ff;
				data = inpw(REG_ECC4F1D) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 1 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				byte = (inpw(REG_ECC4F1A1) >> 16) & 0x1ff;
				data = (inpw(REG_ECC4F1D) >> 8) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 2 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				break;

			case 3:
				byte = inpw(REG_ECC4F1A1) & 0x1ff;
				data = inpw(REG_ECC4F1D) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 1 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				byte = (inpw(REG_ECC4F1A1) >> 16) & 0x1ff;
				data = (inpw(REG_ECC4F1D) >> 8) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 2 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				byte = inpw(REG_ECC4F1A2) & 0x1ff;
				data = (inpw(REG_ECC4F1D) >> 16) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 3 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				break;

			case 4:
				byte = inpw(REG_ECC4F1A1) & 0x1ff;
				data = inpw(REG_ECC4F1D) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 1 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				byte = (inpw(REG_ECC4F1A1) >> 16) & 0x1ff;
				data = (inpw(REG_ECC4F1D) >> 8) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 2 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				byte = inpw(REG_ECC4F1A2) & 0x1ff;
				data = (inpw(REG_ECC4F1D) >> 16) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 3 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				byte = (inpw(REG_ECC4F1A2) >> 16) & 0x1ff;
				data = (inpw(REG_ECC4F1D) >> 24) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 4 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				break;
		}
	}
	if (reg & 0x100)
	{
		errCount = (inpw(REG_ECC4ST) >> 10) & 0x7;
		correct_addr = uDAddr + 0x200;
		switch (errCount)
		{
			case 1:
				byte = inpw(REG_ECC4F2A1) & 0x1ff;
				data = inpw(REG_ECC4F2D) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 1 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				break;

			case 2:
				byte = inpw(REG_ECC4F2A1) & 0x1ff;
				data = inpw(REG_ECC4F2D) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 1 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				byte = (inpw(REG_ECC4F2A1) >> 16) & 0x1ff;
				data = (inpw(REG_ECC4F2D) >> 8) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 2 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				break;

			case 3:
				byte = inpw(REG_ECC4F2A1) & 0x1ff;
				data = inpw(REG_ECC4F2D) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 1 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				byte = (inpw(REG_ECC4F2A1) >> 16) & 0x1ff;
				data = (inpw(REG_ECC4F2D) >> 8) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 2 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				byte = inpw(REG_ECC4F2A2) & 0x1ff;
				data = (inpw(REG_ECC4F2D) >> 16) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 3 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				break;

			case 4:
				byte = inpw(REG_ECC4F2A1) & 0x1ff;
				data = inpw(REG_ECC4F2D) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 1 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				byte = (inpw(REG_ECC4F2A1) >> 16) & 0x1ff;
				data = (inpw(REG_ECC4F2D) >> 8) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 2 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				byte = inpw(REG_ECC4F2A2) & 0x1ff;
				data = (inpw(REG_ECC4F2D) >> 16) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 3 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				byte = (inpw(REG_ECC4F2A2) >> 16) & 0x1ff;
				data = (inpw(REG_ECC4F2D) >> 24) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 4 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				break;
		}
	}
	if (reg & 0x10000)
	{
		errCount = (inpw(REG_ECC4ST) >> 18) & 0x7;
		correct_addr = uDAddr + 0x400;
		switch (errCount)
		{
			case 1:
				byte = inpw(REG_ECC4F3A1) & 0x1ff;
				data = inpw(REG_ECC4F3D) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 1 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				break;

			case 2:
				byte = inpw(REG_ECC4F3A1) & 0x1ff;
				data = inpw(REG_ECC4F3D) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 1 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				byte = (inpw(REG_ECC4F3A1) >> 16) & 0x1ff;
				data = (inpw(REG_ECC4F3D) >> 8) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 2 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				break;

			case 3:
				byte = inpw(REG_ECC4F3A1) & 0x1ff;
				data = inpw(REG_ECC4F3D) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 1 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				byte = (inpw(REG_ECC4F3A1) >> 16) & 0x1ff;
				data = (inpw(REG_ECC4F3D) >> 8) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 2 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				byte = inpw(REG_ECC4F3A2) & 0x1ff;
				data = (inpw(REG_ECC4F3D) >> 16) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 3 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				break;

			case 4:
				byte = inpw(REG_ECC4F3A1) & 0x1ff;
				data = inpw(REG_ECC4F3D) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 1 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				byte = (inpw(REG_ECC4F3A1) >> 16) & 0x1ff;
				data = (inpw(REG_ECC4F3D) >> 8) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 2 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				byte = inpw(REG_ECC4F3A2) & 0x1ff;
				data = (inpw(REG_ECC4F3D) >> 16) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 3 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				byte = (inpw(REG_ECC4F3A2) >> 16) & 0x1ff;
				data = (inpw(REG_ECC4F3D) >> 24) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 4 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				break;
		}
	}
	if (reg & 0x1000000)
	{
		errCount = (inpw(REG_ECC4ST) >> 26) & 0x7;
		correct_addr = uDAddr + 0x600;
		switch (errCount)
		{
			case 1:
				byte = inpw(REG_ECC4F4A1) & 0x1ff;
				data = inpw(REG_ECC4F4D) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 1 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				break;

			case 2:
				byte = inpw(REG_ECC4F4A1) & 0x1ff;
				data = inpw(REG_ECC4F4D) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 1 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				byte = (inpw(REG_ECC4F4A1) >> 16) & 0x1ff;
				data = (inpw(REG_ECC4F4D) >> 8) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 2 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				break;

			case 3:
				byte = inpw(REG_ECC4F4A1) & 0x1ff;
				data = inpw(REG_ECC4F4D) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 1 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				byte = (inpw(REG_ECC4F4A1) >> 16) & 0x1ff;
				data = (inpw(REG_ECC4F4D) >> 8) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 2 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				byte = inpw(REG_ECC4F4A2) & 0x1ff;
				data = (inpw(REG_ECC4F4D) >> 16) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 3 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				break;

			case 4:
				byte = inpw(REG_ECC4F4A1) & 0x1ff;
				data = inpw(REG_ECC4F4D) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 1 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				byte = (inpw(REG_ECC4F4A1) >> 16) & 0x1ff;
				data = (inpw(REG_ECC4F4D) >> 8) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 2 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				byte = inpw(REG_ECC4F4A2) & 0x1ff;
				data = (inpw(REG_ECC4F4D) >> 16) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 3 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				byte = (inpw(REG_ECC4F4A2) >> 16) & 0x1ff;
				data = (inpw(REG_ECC4F4D) >> 24) & 0xff;
				writeb(correct_addr+byte, readb(correct_addr+byte)^(data & 0xff));
#ifdef DEBUG
				printf("correctable 4 byte!! correct_addr[%x], byte[%x], data[%x]\n", correct_addr, byte, data);
				printf("correct data [%x]\n", readb(correct_addr+byte));
#endif
				break;
		}
	}
	return 0;
}


INT fmiSM_Read_2K(FMI_SM_INFO_T *pSM, UINT32 uPage, UINT32 uDAddr)
{
	if ((_fmi_nPreState == FMI_SM_WRITE) || (_fmi_nPreState == FMI_SM_ERASE))
	{
		if (!fmiSMCheckRB())
			return FMI_SM_RB_ERR;

		outpw(REG_SMCMD, 0x70);		// status read command
		if (inpw(REG_SMDATA) & 0x01)	// 1:fail; 0:pass
		{
#ifdef DEBUG
			printf("fmiSM_Write_2K: data error!!\n");
#endif
			return FMI_SM_STATE_ERROR;
		}
	}

	outpw(REG_DMACSAR2, uDAddr);	// set DMA transfer starting address

	if (_fmi_nPreState == FMI_SM_READ)
	{
		/* clear R/B flag */
		while(!(inpw(REG_SMISR) & 0x40000));
		outpw(REG_SMISR, 0x400);
	}

	outpw(REG_SMCMD, 0x00);		// read command
	outpw(REG_SMADDR, 0);	// CA0 - CA7
	outpw(REG_SMADDR, 0);	// CA8 - CA11
	outpw(REG_SMADDR, uPage & 0xff);	// PA0 - PA7
	if (!pSM->bIsMulticycle)
		outpw(REG_SMADDR, ((uPage >> 8) & 0xff)|0x80000000);		// PA8 - PA15
	else
	{
		outpw(REG_SMADDR, (uPage >> 8) & 0xff);		// PA8 - PA15
		outpw(REG_SMADDR, ((uPage >> 16) & 0xff)|0x80000000);		// PA16 - PA17
	}
	outpw(REG_SMCMD, 0x30);		// read command
	_fmi_nPreState = FMI_SM_READ;

	if (!fmiSMCheckRB())
		return FMI_SM_RB_ERR;

	_fmi_bIsSMDataReady = FALSE;

	outpw(REG_SMCSR, inpw(REG_SMCSR) | 0x02);

	while(!_fmi_bIsSMDataReady);

	// check ECC
	if (inpw(REG_SMISR) & 0x02)
	{
#ifdef DEBUG
		printf("ECC error! Page[%d]\n", uPage);
#endif
		outpw(REG_SMISR, 0x02);
		return fmiSMCorrectData_2K(uDAddr);
	}
	return 0;
}


INT fmiSM_Read_2K_RA(FMI_SM_INFO_T *pSM, UINT32 uPage, UINT32 ucColAddr)
{
	if ((_fmi_nPreState == FMI_SM_WRITE) || (_fmi_nPreState == FMI_SM_ERASE))
	{
		if (!fmiSMCheckRB())
			return FMI_SM_RB_ERR;

		outpw(REG_SMCMD, 0x70);		// status read command
		if (inpw(REG_SMDATA) & 0x01)	// 1:fail; 0:pass
		{
#ifdef DEBUG
			printf("fmiSM_Write_2K: data error!!\n");
#endif
			return FMI_SM_STATE_ERROR;
		}
	}

	if (_fmi_nPreState == FMI_SM_READ)
	{
		/* clear R/B flag */
		while(!(inpw(REG_SMISR) & 0x40000));
		outpw(REG_SMISR, 0x400);
	}

	outpw(REG_SMCMD, 0x00);		// read command
	outpw(REG_SMADDR, ucColAddr);	// CA0 - CA7
	outpw(REG_SMADDR, (ucColAddr >> 8) & 0x0f);	// CA8 - CA11
	outpw(REG_SMADDR, uPage & 0xff);	// PA0 - PA7
	if (!pSM->bIsMulticycle)
		outpw(REG_SMADDR, ((uPage >> 8) & 0xff)|0x80000000);		// PA8 - PA15
	else
	{
		outpw(REG_SMADDR, (uPage >> 8) & 0xff);		// PA8 - PA15
		outpw(REG_SMADDR, ((uPage >> 16) & 0xff)|0x80000000);		// PA16 - PA17
	}
	outpw(REG_SMCMD, 0x30);		// read command
	_fmi_nPreState = FMI_SM_READ;

	if (!fmiSMCheckRB())
		return FMI_SM_RB_ERR;

	return 0;
}



INT fmiSM_Read_2Plane(FMI_SM_INFO_T *pSM, UINT32 PBA, UINT32 uPage, UINT32 uDAddr)
{
	int status;
	UINT32 pageNo;

	if ((_fmi_nPreState == FMI_SM_WRITE) || (_fmi_nPreState == FMI_SM_ERASE))
	{
		if (!fmiSMCheckRB())
		{
#ifdef DEBUG
			printf("1. fmiSM_Write_2Plane: R/B- timeout!!\n");
#endif
			return FMI_SM_RB_ERR;
		}

		outpw(REG_SMCMD, 0x70);		// status read command
		if (inpw(REG_SMDATA) & 0x01)	// 1:fail; 0:pass
		{
#ifdef DEBUG
			printf("fmiSM_Write_2Plane: data error!!\n");
#endif
			return FMI_SM_STATE_ERROR;
		}
	}

	outpw(REG_DMACSAR2, uDAddr);	// set DMA transfer starting address

	if (_fmi_nPreState == FMI_SM_READ)
	{
		/* clear R/B flag */
		while(!(inpw(REG_SMISR) & 0x40000));
		outpw(REG_SMISR, 0x400);
	}

	pageNo = (PBA << 1) * pSM->uPagePerBlock + uPage;
	outpw(REG_SMCMD, 0x00);		// read command
	outpw(REG_SMADDR, 0);	// CA0 - CA7
	outpw(REG_SMADDR, 0);	// CA8 - CA11
	outpw(REG_SMADDR, pageNo & 0xff);	// PA0 - PA7
	if (!pSM->bIsMulticycle)
		outpw(REG_SMADDR, ((pageNo >> 8) & 0xff)|0x80000000);		// PA8 - PA15
	else
	{
		outpw(REG_SMADDR, (pageNo >> 8) & 0xff);		// PA8 - PA15
		outpw(REG_SMADDR, ((pageNo >> 16) & 0x0f)|0x80000000);		// PA16 - PA17
	}
	outpw(REG_SMCMD, 0x30);		// read command

	if (!fmiSMCheckRB())
	{
#ifdef DEBUG
		printf("2. fmiSM_Write_2Plane: R/B- timeout!!\n");
#endif
		return FMI_SM_RB_ERR;
	}

	_fmi_bIsSMDataReady = FALSE;

	outpw(REG_SMCSR, inpw(REG_SMCSR) | 0x02);

	while(!_fmi_bIsSMDataReady);

	// check ECC
	if (inpw(REG_SMISR) & 0x02)
	{
#ifdef DEBUG
		printf("ECC error! Page[%d]\n", pageNo);
#endif
		outpw(REG_SMISR, 0x02);
		status = fmiSMCorrectData_2K(uDAddr);
		if (status < 0)
			return status;
	}

	outpw(REG_DMACSAR2, uDAddr+2048);	// set DMA transfer starting address

	if (_fmi_nPreState == FMI_SM_READ)
	{
		/* clear R/B flag */
		while(!(inpw(REG_SMISR) & 0x40000));
		outpw(REG_SMISR, 0x400);
	}

	pageNo = ((PBA << 1) + 1) * pSM->uPagePerBlock + uPage;
	outpw(REG_SMCMD, 0x00);		// read command
	outpw(REG_SMADDR, 0);	// CA0 - CA7
	outpw(REG_SMADDR, 0);	// CA8 - CA11
	outpw(REG_SMADDR, pageNo & 0xff);	// PA0 - PA7
	if (!pSM->bIsMulticycle)
		outpw(REG_SMADDR, ((pageNo >> 8) & 0xff)|0x80000000);		// PA8 - PA15
	else
	{
		outpw(REG_SMADDR, (pageNo >> 8) & 0xff);		// PA8 - PA15
		outpw(REG_SMADDR, ((pageNo >> 16) & 0x0f)|0x80000000);		// PA16 - PA17
	}
	outpw(REG_SMCMD, 0x30);		// read command
	_fmi_nPreState = FMI_SM_READ;

	if (!fmiSMCheckRB())
		return FMI_SM_RB_ERR;

	_fmi_bIsSMDataReady = FALSE;

	outpw(REG_SMCSR, inpw(REG_SMCSR) | 0x02);

	while(!_fmi_bIsSMDataReady);

	// check ECC
	if (inpw(REG_SMISR) & 0x02)
	{
#ifdef DEBUG
		printf("ECC error! Page[%d]\n", pageNo);
#endif
		outpw(REG_SMISR, 0x02);
		return fmiSMCorrectData_2K(uDAddr+2048);
	}
	return 0;
}


INT fmiSM_Read_2Plane_RA(FMI_SM_INFO_T *pSM, UINT32 uPage, UINT32 ucColAddr)
{
	if ((_fmi_nPreState == FMI_SM_WRITE) || (_fmi_nPreState == FMI_SM_ERASE))
	{
		if (!fmiSMCheckRB())
		{
#ifdef DEBUG
			printf("1. fmiSM_Write_2Plane: R/B- timeout!!\n");
#endif
			return FMI_SM_RB_ERR;
		}

		outpw(REG_SMCMD, 0x70);		// status read command
		if (inpw(REG_SMDATA) & 0x01)	// 1:fail; 0:pass
		{
#ifdef DEBUG
			printf("fmiSM_Write_2Plane: data error!!\n");
#endif
			return FMI_SM_STATE_ERROR;
		}
	}

	if (_fmi_nPreState == FMI_SM_READ)
	{
		/* clear R/B flag */
		while(!(inpw(REG_SMISR) & 0x40000));
		outpw(REG_SMISR, 0x400);
	}

	outpw(REG_SMCMD, 0x00);		// read command
	outpw(REG_SMADDR, ucColAddr);	// CA0 - CA7
	outpw(REG_SMADDR, (ucColAddr >> 8) & 0x0f);	// CA8 - CA11
	outpw(REG_SMADDR, uPage & 0xff);	// PA0 - PA7
	if (!pSM->bIsMulticycle)
		outpw(REG_SMADDR, ((uPage >> 8) & 0xff)|0x80000000);		// PA8 - PA15
	else
	{
		outpw(REG_SMADDR, (uPage >> 8) & 0xff);		// PA8 - PA15
		outpw(REG_SMADDR, ((uPage >> 16) & 0x0f)|0x80000000);		// PA16 - PA17
	}
	outpw(REG_SMCMD, 0x30);		// read command
	_fmi_nPreState = FMI_SM_READ;

	if (!fmiSMCheckRB())
		return FMI_SM_RB_ERR;

	return 0;
}


INT fmiSM_Write_2K(FMI_SM_INFO_T *pSM, UINT32 uSector, UINT32 ucColAddr, UINT32 uSAddr)
{
	if ((_fmi_nPreState == FMI_SM_WRITE) || (_fmi_nPreState == FMI_SM_ERASE))
	{
		if (!fmiSMCheckRB())
			return FMI_SM_RB_ERR;

		outpw(REG_SMCMD, 0x70);		// status read command
		if (inpw(REG_SMDATA) & 0x01)	// 1:fail; 0:pass
		{
#ifdef DEBUG
			printf("fmiSM_Write_2K: data error!!\n");
#endif
			return FMI_SM_STATE_ERROR;
		}
	}

	outpw(REG_DMACSAR2, uSAddr);	// set DMA transfer starting address

	// set the spare area configuration
	/* write byte 2050, 2051 as used page */
	outpw(REG_SMRA_0, 0x0000FFFF);
	outpw(REG_SMRA_4, 0x0000FFFF);
	outpw(REG_SMRA_8, 0x0000FFFF);
	outpw(REG_SMRA_12, 0x0000FFFF);

	if (_fmi_nPreState == FMI_SM_READ)
	{
		/* clear R/B flag */
		while(!(inpw(REG_SMISR) & 0x40000));
		outpw(REG_SMISR, 0x400);
	}

	// send command
	outpw(REG_SMCMD, 0x80);		// serial data input command
	outpw(REG_SMADDR, ucColAddr);	// CA0 - CA7
	outpw(REG_SMADDR, (ucColAddr >> 8) & 0x0f);	// CA8 - CA11
	outpw(REG_SMADDR, uSector & 0xff);	// PA0 - PA7
	if (!pSM->bIsMulticycle)
		outpw(REG_SMADDR, ((uSector >> 8) & 0xff)|0x80000000);		// PA8 - PA15
	else
	{
		outpw(REG_SMADDR, (uSector >> 8) & 0xff);		// PA8 - PA15
		outpw(REG_SMADDR, ((uSector >> 16) & 0xff)|0x80000000);		// PA16 - PA17
	}

	_fmi_bIsSMDataReady = FALSE;

	outpw(REG_SMCSR, inpw(REG_SMCSR) | 0x04);

	while(!_fmi_bIsSMDataReady);

	outpw(REG_SMCMD, 0x10);		// auto program command
	_fmi_nPreState = FMI_SM_WRITE;

	return 0;
}


INT fmiSM_Write_2Plane(FMI_SM_INFO_T *pSM, UINT32 uSector, UINT32 ucColAddr, UINT32 uSAddr)
{
	if ((_fmi_nPreState == FMI_SM_WRITE) || (_fmi_nPreState == FMI_SM_ERASE))
	{
		if (!fmiSMCheckRB())
			return FMI_SM_RB_ERR;

		outpw(REG_SMCMD, 0x70);		// status read command
		if (inpw(REG_SMDATA) & 0x01)	// 1:fail; 0:pass
		{
#ifdef DEBUG
			printf("fmiSM_Write_2Plane: data error!!\n");
#endif
			return FMI_SM_STATE_ERROR;
		}
	}

	/* first page */
	outpw(REG_DMACSAR2, uSAddr);	// set DMA transfer starting address

	/* write byte 2050, 2051 as used page */
	outpw(REG_SMRA_0, 0x0000FFFF);
	outpw(REG_SMRA_4, 0x0000FFFF);
	outpw(REG_SMRA_8, 0x0000FFFF);
	outpw(REG_SMRA_12, 0x0000FFFF);

	if (_fmi_nPreState == FMI_SM_READ)
	{
		/* clear R/B flag */
		while(!(inpw(REG_SMISR) & 0x40000));
		outpw(REG_SMISR, 0x400);
	}

	// send command
	outpw(REG_SMCMD, 0x80);		// serial data input command
	outpw(REG_SMADDR, 0);	// CA0 - CA7
	outpw(REG_SMADDR, 0);	// CA8 - CA11
	outpw(REG_SMADDR, 0);	// PA0 - PA7
	outpw(REG_SMADDR, 0);		// PA8 - PA15
	outpw(REG_SMADDR, ((uSector >> 16) & 0x08)|0x80000000);		// PA16 - PA17

	_fmi_bIsSMDataReady = FALSE;

	outpw(REG_SMCSR, inpw(REG_SMCSR) | 0x04);

	while(!_fmi_bIsSMDataReady);

	outpw(REG_SMCMD, 0x11);		// auto program command
	if (!fmiSMCheckRB())
		return FMI_SM_RB_ERR;

	/* second page */
	outpw(REG_DMACSAR2, uSAddr+2048);	// set DMA transfer starting address

	/* write byte 2050, 2051 as used page */
	outpw(REG_SMRA_0, 0x0000FFFF);
	outpw(REG_SMRA_4, 0x0000FFFF);
	outpw(REG_SMRA_8, 0x0000FFFF);
	outpw(REG_SMRA_12, 0x0000FFFF);

	// send command
	outpw(REG_SMCMD, 0x81);		// serial data input command
	outpw(REG_SMADDR, 0);	// CA0 - CA7
	outpw(REG_SMADDR, 0);	// CA8 - CA11
	outpw(REG_SMADDR, (uSector & 0xff)|0x80);	// PA0 - PA7
	outpw(REG_SMADDR, (uSector >> 8) & 0xff);		// PA8 - PA15
	outpw(REG_SMADDR, ((uSector >> 16) & 0x0f)|0x80000000);		// PA16 - PA17

	_fmi_bIsSMDataReady = FALSE;

	outpw(REG_SMCSR, inpw(REG_SMCSR) | 0x04);

	while(!_fmi_bIsSMDataReady);

	outpw(REG_SMCMD, 0x10);		// auto program command
	_fmi_nPreState = FMI_SM_WRITE;

	return 0;
}


INT fmiSMCheckBootHeader(FMI_SM_INFO_T *pSM)
{
	int volatile status, imageCount, i, infoPage;
	unsigned int *pImageList;
	UCHAR _fmi_ucSMBuffer[2048];
	UINT8 *_fmi_pSMBuffer;

	_fmi_pSMBuffer = (UINT8 *)((UINT32)_fmi_ucSMBuffer | 0x80000000);
	pImageList = (UINT32 *)((UINT32)_fmi_ucSMBuffer | 0x80000000);

	if (inpw(0xFFFF0014) == 0x20070502)
		infoPage = 5;
	else /* CB later version */
		infoPage = pSM->uPagePerBlock-2;

	/* read physical block 0 - image information */
	if (pSM->bIs2KPageSize == 0)	// 512
	{
		status = fmiSM_Read_512(pSM, infoPage, (UINT32)_fmi_pSMBuffer);
		if (status < 0)
			return status;
	}
	else
	{
		status = fmiSM_Read_2K(pSM, infoPage, (UINT32)_fmi_pSMBuffer);
		if (status < 0)
			return status;
	}

	if (((*(pImageList+0)) == 0x574255aa) && ((*(pImageList+3)) == 0x57425963))
	{
		imageCount = *(pImageList+1);

		/* pointer to image information */
		pImageList = pImageList+4;
		for (i=0; i<imageCount; i++)
		{
			pSM->uLibStartBlock = (*(pImageList + 1) & 0xFFFF0000) >> 16;

			/* pointer to next image */
			pImageList = pImageList+8;
		}
		pSM->uLibStartBlock++;
	}
	return 0;
}

INT fmiCheckInvalidBlock(FMI_SM_INFO_T *pSM, UINT32 BlockNo)
{
	int volatile status=0;
	unsigned int volatile sector;

	/* MLC check the 2048 byte of last page per block */
	if (pSM->bIsMLCNand == TRUE)
	{
		if (gbIsSupport2PlaneNand)
		{
			sector = ((BlockNo << 1) + 2) * pSM->uPagePerBlock - 1;
			/* Read 2048 byte */
			status = fmiSM_Read_2K_RA(pSM, sector, 2048);
			if (status < 0)
				return status;
			if ((inpw(REG_SMDATA) & 0xff) != 0xFF)
				return 1;	// invalid block

			sector = ((BlockNo << 1) + 1) * pSM->uPagePerBlock - 1;
			/* Read 2048 byte */
			status = fmiSM_Read_2K_RA(pSM, sector, 2048);
			if (status < 0)
				return status;
			if ((inpw(REG_SMDATA) & 0xff) != 0xFF)
				return 1;	// invalid block
		}
		else
		{
			sector = (BlockNo+1) * pSM->uPagePerBlock - 1;
			/* Read 2048 byte */
			status = fmiSM_Read_2K_RA(pSM, sector, 2048);
			if (status < 0)
				return status;
			if ((inpw(REG_SMDATA) & 0xff) != 0xFF)
				return 1;	// invalid block
		}
	}
	/* SLC check the 2048 byte of 1st or 2nd page per block */
	else	// SLC
	{
		sector = BlockNo * pSM->uPagePerBlock;
		if (pSM->bIs2KPageSize == TRUE)
		{
			status = fmiSM_Read_2K_RA(pSM, sector, 2048);
			if (status < 0)
				return status;
			if ((inpw(REG_SMDATA) & 0xff) != 0xFF)
			{
				status = fmiSM_Read_2K_RA(pSM, sector+1, 2048);
				if (status < 0)
					return status;
				if ((inpw(REG_SMDATA) & 0xff) != 0xFF)
				{
					return 1;	// invalid block
				}
			}
		}
		else	/* page size 512B */
		{
			status = fmiSM2BufferM_RA(pSM, sector, 0);
			if (status < 0)
				return status;
			if ((inpw(REG_SMDATA) & 0xff) != 0xFF)
			{
				fmiSM_Reset();
				status = fmiSM2BufferM_RA(pSM, sector+1, 0);
				if (status < 0)
					return status;
				if ((inpw(REG_SMDATA) & 0xff) != 0xFF)
				{
					fmiSM_Reset();
					return 1;	// invalid block
				}
			}
			fmiSM_Reset();
		}
	}

	return 0;
}


/* function pointer */
FMI_SM_INFO_T *pSM0, *pSM1;
static INT sicSMInit(INT NandPort, NDISK_T *NDISK_info)
{
	int status=0;

	// enable SM
	outpw(REG_FMICSR, 0x08);

	switch (_fmi_uFMIReferenceClock)
	{
		case 200000:	// AHB = 100MHz
		case 100000:	// AHB = 100MHz
			outpw(REG_SMTCR, 0x10204);
			break;

		case 166000:	// AHB = 83MHz
			outpw(REG_SMTCR, 0x10203);
			break;

		case 133000:	// AHB = 133MHz
			outpw(REG_SMTCR, 0x10305);
			break;

		case 66000:	// AHB = 66MHz
			outpw(REG_SMTCR, 0x10203);
			break;

		default:
			;
	}

	//outpw(REG_SMTCR, 0x4050b);
	if (NandPort == 0)
	{
		/* init SM interface */
		outpw(REG_SMCSR, (inpw(REG_SMCSR)&0xf8ffffc0)|0x01000020);	// enable ecc4

		pSM0 = malloc(sizeof(FMI_SM_INFO_T));
		memset((char *)pSM0, 0, sizeof(FMI_SM_INFO_T));

		if ((status = fmiSM_ReadID(pSM0, NDISK_info)) < 0)
			return status;
		fmiSM_Initial(pSM0);

		// check NAND boot header
		fmiSMCheckBootHeader(pSM0);
		while(1)
		{
			if (fmiCheckInvalidBlock(pSM0, pSM0->uLibStartBlock) != 1)	// valid block
				break;
			else
				pSM0->uLibStartBlock++;
		}
		NDISK_info->nStartBlock = pSM0->uLibStartBlock;		/* available start block */
		pSM0->uBlockPerFlash -= pSM0->uLibStartBlock;
	}
	else
	{
		/* init SM interface */
		outpw(REG_SMCSR, (inpw(REG_SMCSR)&0xf8ffffc0)|0x03000020);	// enable ecc4

		pSM1 = malloc(sizeof(FMI_SM_INFO_T));
		memset((char *)pSM1, 0, sizeof(FMI_SM_INFO_T));

		if ((status = fmiSM_ReadID(pSM1, NDISK_info)) < 0)
			return status;
		fmiSM_Initial(pSM1);

		// check NAND boot header
		fmiSMCheckBootHeader(pSM1);
		while(1)
		{
			if (fmiCheckInvalidBlock(pSM1, pSM1->uLibStartBlock) != 1)	// valid block
				break;
			else
				pSM1->uLibStartBlock++;
		}
		NDISK_info->nStartBlock = pSM1->uLibStartBlock;		/* available start block */
		pSM1->uBlockPerFlash -= pSM1->uLibStartBlock;
	}

	NDISK_info->nBlockPerZone = (NDISK_info->nBlockPerZone * NDISK_info->nZone - NDISK_info->nStartBlock) / NDISK_info->nZone;
	NDISK_info->nLBPerZone = NDISK_info->nBlockPerZone - 20;

	return 0;
}

static INT sicSMpread(INT NandPort, INT PBA, INT page, UINT8 *buff)
{
	FMI_SM_INFO_T *pSM;
	int pageNo;

	if (NandPort == 0)
		pSM = pSM0;
	else
		pSM = pSM1;

	// enable SM
	outpw(REG_FMICSR, 0x08);

	if (gbIsSupport2PlaneNand)
	{
		PBA += (pSM->uLibStartBlock/2);
		if ((pSM->uLibStartBlock%2) != 0)
			PBA++;
		//pageNo = (PBA << 1) * pSM->uPagePerBlock + page;
		return (fmiSM_Read_2Plane(pSM, PBA, page, (UINT32)buff));
	}
	else
	{
		PBA += pSM->uLibStartBlock;
		pageNo = PBA * pSM->uPagePerBlock + page;
		if (pSM->bIs2KPageSize)	/* 2KB */
			return (fmiSM_Read_2K(pSM, pageNo, (UINT32)buff));
		else	/* 512B */
			return (fmiSM_Read_512(pSM, pageNo, (UINT32)buff));
	}
}

static INT sicSMpwrite(INT NandPort, INT PBA, INT page, UINT8 *buff)
{
	FMI_SM_INFO_T *pSM;
	int pageNo;

	if (NandPort == 0)
		pSM = pSM0;
	else
		pSM = pSM1;

	// enable SM
	outpw(REG_FMICSR, 0x08);

	if (gbIsSupport2PlaneNand)
	{
		PBA += (pSM->uLibStartBlock/2);
		if ((pSM->uLibStartBlock%2) != 0)
			PBA++;
		pageNo = (PBA << 1) * pSM->uPagePerBlock + page;
		return (fmiSM_Write_2Plane(pSM, pageNo, 0, (UINT32)buff));
	}
	else
	{
		PBA += pSM->uLibStartBlock;
		pageNo = PBA * pSM->uPagePerBlock + page;
		if (pSM->bIs2KPageSize)	/* 2KB */
			return (fmiSM_Write_2K(pSM, pageNo, 0, (UINT32)buff));
		else	/* 512B */
			return (fmiSM_Write_512(pSM, pageNo, (UINT32)buff));
	}
}

static INT sicSM_is_page_dirty(INT NandPort, INT PBA, INT page)
{
	FMI_SM_INFO_T *pSM;
	int pageNo;
	UINT8 data0, data1;

	if (NandPort == 0)
		pSM = pSM0;
	else
		pSM = pSM1;

	// enable SM
	outpw(REG_FMICSR, 0x08);

	if (gbIsSupport2PlaneNand)
	{
		PBA += (pSM->uLibStartBlock/2);
		if ((pSM->uLibStartBlock%2) != 0)
			PBA++;
		pageNo = (PBA << 1) * pSM->uPagePerBlock + page;
		fmiSM_Read_2K_RA(pSM, pageNo, 2050);
	}
	else
	{
		PBA += pSM->uLibStartBlock;
		pageNo = PBA * pSM->uPagePerBlock + page;
		if (pSM->bIs2KPageSize)	/* 2KB */
			fmiSM_Read_2K_RA(pSM, pageNo, 2050);
		else	/* 512B */
			fmiSM2BufferM_RA(pSM, pageNo, 2);
	}
	data0 = inpw(REG_SMDATA);
	data1 = inpw(REG_SMDATA);

	if (!pSM->bIs2KPageSize)	/* 512B */
		fmiSM_Reset();

	if ((data0 == 0) && (data1 == 0x00))
		return 1;	// used page

	return 0;	// un-used page
}


static INT sicSM_is_valid_block(INT NandPort, INT PBA)
{
	FMI_SM_INFO_T *pSM;

	if (NandPort == 0)
		pSM = pSM0;
	else
		pSM = pSM1;

	if (gbIsSupport2PlaneNand)
	{
		PBA += (pSM->uLibStartBlock/2);
		if ((pSM->uLibStartBlock%2) != 0)
			PBA++;
	}
	else
		PBA += pSM->uLibStartBlock;

	// enable SM
	outpw(REG_FMICSR, 0x08);

	if (fmiCheckInvalidBlock(pSM, PBA) == 1)	// invalid block
		return 0;
	else
		return 1;	// valid block
}


static INT sicSMblock_erase(INT NandPort, INT PBA)
{
	FMI_SM_INFO_T *pSM;
	UINT32 page_no;

	if (NandPort == 0)
		pSM = pSM0;
	else
		pSM = pSM1;

	PBA += pSM->uLibStartBlock;

	// enable SM
	outpw(REG_FMICSR, 0x08);

	if (fmiCheckInvalidBlock(pSM, PBA) != 1)
	{
		page_no = PBA * pSM->uPagePerBlock;		// get page address

		//fmiSM_Reset();

		if ((_fmi_nPreState == FMI_SM_WRITE) || (_fmi_nPreState == FMI_SM_ERASE))
		{
			if (!fmiSMCheckRB())
				return FMI_SM_RB_ERR;

			outpw(REG_SMCMD, 0x70);		// status read command
			if (inpw(REG_SMDATA) & 0x01)	// 1:fail; 0:pass
			{
#ifdef DEBUG
				printf("sicSMblock_erase error!!\n");
#endif
				return FMI_SM_STATUS_ERR;
			}
		}

		if (_fmi_nPreState == FMI_SM_READ)
		{
			/* clear R/B flag */
			while(!(inpw(REG_SMISR) & 0x40000));
			outpw(REG_SMISR, 0x400);
		}

		outpw(REG_SMCMD, 0x60);		// erase setup command

		outpw(REG_SMADDR, (page_no & 0xff));		// PA0 - PA7
		if (!pSM->bIsMulticycle)
			outpw(REG_SMADDR, ((page_no >> 8) & 0xff)|0x80000000);		// PA8 - PA15
		else
		{
			outpw(REG_SMADDR, ((page_no >> 8) & 0xff));		// PA8 - PA15
			outpw(REG_SMADDR, ((page_no >> 16) & 0xff)|0x80000000);		// PA16 - PA17
		}
	
		outpw(REG_SMCMD, 0xd0);		// erase command
		_fmi_nPreState = FMI_SM_ERASE;
	}
	else
		return FMI_SM_INVALID_BLOCK;
	return 0;
}

static INT sicSMblock_erase_2Plane(INT NandPort, INT PBA)
{
	FMI_SM_INFO_T *pSM;
	UINT32 page_no;

	if (NandPort == 0)
		pSM = pSM0;
	else
		pSM = pSM1;

	PBA += (pSM->uLibStartBlock / 2);
	if ((pSM->uLibStartBlock % 2) != 0)
		PBA++;

	// enable SM
	outpw(REG_FMICSR, 0x08);

	if (fmiCheckInvalidBlock(pSM, PBA) != 1)
	{
		page_no = (PBA << 1) * pSM->uPagePerBlock;		// get page address

		if ((_fmi_nPreState == FMI_SM_WRITE) || (_fmi_nPreState == FMI_SM_ERASE))
		{
			if (!fmiSMCheckRB())
				return FMI_SM_RB_ERR;

			outpw(REG_SMCMD, 0x70);		// status read command
			if (inpw(REG_SMDATA) & 0x01)	// 1:fail; 0:pass
			{
#ifdef DEBUG
				printf("sicSMblock_erase_2Plane error!!\n");
#endif
				return FMI_SM_STATUS_ERR;
			}
		}

		if (_fmi_nPreState == FMI_SM_READ)
		{
			/* clear R/B flag */
			while(!(inpw(REG_SMISR) & 0x40000));
			outpw(REG_SMISR, 0x400);
		}

		/* first block */
		outpw(REG_SMCMD, 0x60);		// erase setup command

		outpw(REG_SMADDR, 0);		// PA0 - PA7
		outpw(REG_SMADDR, 0);		// PA8 - PA15
		outpw(REG_SMADDR, ((page_no  >> 16) & 0x0f)|0x80000000);		// PA16 - PA17
	
		outpw(REG_SMCMD, 0x60);		// erase setup command

		outpw(REG_SMADDR, 0x80);		// PA0 - PA7
		outpw(REG_SMADDR, ((page_no >> 8) & 0xff));		// PA8 - PA15
		outpw(REG_SMADDR, ((page_no >> 16) & 0x0f)|0x80000000);		// PA16 - PA17
	
		outpw(REG_SMCMD, 0xd0);		// erase command
		_fmi_nPreState = FMI_SM_ERASE;
	}
	else
		return FMI_SM_INVALID_BLOCK;

	return 0;
}


static INT sicSMchip_erase(INT NandPort)
{
	int i, status=0;
	FMI_SM_INFO_T *pSM;

	if (NandPort == 0)
		pSM = pSM0;
	else
		pSM = pSM1;

	// enable SM
	outpw(REG_FMICSR, 0x08);

	// erase all chip
	if (gbIsSupport2PlaneNand)
	{
		for (i=0; i<=(pSM->uBlockPerFlash/2); i++)
		{
			status = sicSMblock_erase_2Plane(NandPort, i);
#ifdef DEBUG
			if (status < 0)
				printf("SM block erase fail <%d>!!\n", i);
#endif
		}
	}
	else
	{
		for (i=0; i<=pSM->uBlockPerFlash; i++)
		{
			status = sicSMblock_erase(NandPort, i);
#ifdef DEBUG
			if (status < 0)
				printf("SM block erase fail <%d>!!\n", i);
#endif
		}
	}

	return status;
}

/* driver function */
INT nandInit0(NDISK_T *NDISK_info)
{
	return (sicSMInit(0, NDISK_info));
}

INT nandpread0(INT PBA, INT page, UINT8 *buff)
{
	return (sicSMpread(0, PBA, page, buff));
}

INT nandpwrite0(INT PBA, INT page, UINT8 *buff)
{
	return (sicSMpwrite(0, PBA, page, buff));
}

INT nand_is_page_dirty0(INT PBA, INT page)
{
	return (sicSM_is_page_dirty(0, PBA, page));
}

INT nand_is_valid_block0(INT PBA)
{
	return (sicSM_is_valid_block(0, PBA));
}

INT nand_block_erase0(INT PBA)
{
	if (gbIsSupport2PlaneNand)
		return (sicSMblock_erase_2Plane(0, PBA));
	else
		return (sicSMblock_erase(0, PBA));
}

INT nand_chip_erase0(VOID)
{
	return (sicSMchip_erase(0));
}

INT nand_ioctl(INT param1, INT param2, INT param3, INT param4)
{
	return 0;
}

INT nandInit1(NDISK_T *NDISK_info)
{
	return (sicSMInit(1, NDISK_info));
}

INT nandpread1(INT PBA, INT page, UINT8 *buff)
{
	return (sicSMpread(1, PBA, page, buff));
}

INT nandpwrite1(INT PBA, INT page, UINT8 *buff)
{
	return (sicSMpwrite(1, PBA, page, buff));
}

INT nand_is_page_dirty1(INT PBA, INT page)
{
	return (sicSM_is_page_dirty(1, PBA, page));
}

INT nand_is_valid_block1(INT PBA)
{
	return (sicSM_is_valid_block(1, PBA));
}

INT nand_block_erase1(INT PBA)
{
	if (gbIsSupport2PlaneNand)
		return (sicSMblock_erase_2Plane(1, PBA));
	else
		return (sicSMblock_erase(1, PBA));
}

INT nand_chip_erase1(VOID)
{
	return (sicSMchip_erase(1));
}





